/*  

Cafechess Library: Cover basic chess programming needs, like GUI, Engine integration, 
FEN and PGN parsing.

                 \\|//
                 (o o)
--------------ooO-(_)-Ooo----------------------------------
Copyright (C) 2009  By Gregory A. Prentice Snoqualmie, WA
                    www.cafechess.org
                    cafechess@comcast.net
                      Oooo
--------------oooO----(  )---------------------------------
              (  )    (_/
               \_)

Microsoft Public License (Ms-PL)
               
Revisions:

Author        Date    Description:

*/
using System;
using System.Collections;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Configuration;

using Cafechess.Threading;
using Cafechess.Text.Commands;

namespace Cafechess.Chess.Engines.WBD
{
	/// <summary>
	/// Defines our interface to the XBoard chess engine standards.  We can
	/// attach to, send and receive messages with the chess engine.  The main 
	/// command parsing is performed with regular expressions.  By assigning
	/// a regular expression that extracts the specific engine command, we
	/// should be able to create interfaces to multiple xboard engines.
	/// Below is an example of the app.conf file for the Crafty chess engine
	/// see the demo application that should have been distributed with
	/// this library.  The following is an example of how to add Crafty
	/// directly through Xboard.AddCommand.
  /// <code>
  ///  AddCommand("EngineMove","(^move) +(.*)");
  ///  AddCommand("EngineError, "(^Error) +(.*)");
  ///  AddCommand("EngineIllegalMove","(^Illegal move:?) +(.*)");
  ///  AddCommand("EngineResults","(^[01]-[01]) +(.*)");
  ///  AddCommand("EngineResults","(^1/2-1/2) +(.*)");
  ///  AddCommand("EngineResults",^resign) +(.*)");
  ///  AddCommand("EngineOfferDraw","(^offer draw) +(.*)");
  ///  AddCommand("EngineInfo","(^feature) +(.*)");
  ///  AddCommand("EngineTellOpponent""(^tellopponent) +(.*)");
  ///  AddCommand("EngineTellOthers","(^tellothers) +(.*)");
  ///  AddCommand("EngineTellAll","(^tellall) +(.*)");
  ///  AddCommand("EngineTellUser","(^telluser) +(.*)");
  ///  AddCommand("EngineTellUserError","(^tellusererror) +(.*)");
  ///  AddCommand("EngineAskUser","(^askuser) +(.*)");
  ///  AddCommand("EngineTellIcs","(^tellics) +(.*)");
  ///  AddCommand("EngineTellIcsNoAlias","(^tellicsnoalias) +(.*)");
  ///  AddCommand("EngineAnalysis","([0-9]+)[^-\w]+(-?[0-9]+)\W+([0-9]+)\W+([0-9]+)\W+(.*)");
  /// </code>
  /// </summary>
	public class Xboard : Engine
  {
    /// <summary>
    /// Construction of our Xboard engine interface.
    /// </summary>
    /// <param name="ievents"></param>
    /// <param name="ci"></param>
    public Xboard(IChessEngineEvents ievents,ChessEngineInterface ci)
      : base(ievents, ci)
    {
    }

    #region IChessEngine Members
    override public void NewGame()
    {
      if (IsRunning())
      {
        coEngine.StandardInput.WriteLine("new");
        coEngine.StandardInput.Flush();
      }
    }
    /// <summary>
    /// Turn on or off the pondering or thinking of the engine.
    /// </summary>
    /// <param name="turnOn"></param>
    override public void Ponder(bool turnOn)
    {
      if (IsRunning())
      {
        coEngine.StandardInput.WriteLine(turnOn ? "post" : "nopost");
        coEngine.StandardInput.Flush();
      }
    }
    /// <summary>
    /// Sends a force current move command to the engine.
    /// </summary>
    override public void Force()
    {
      if (IsRunning())
      {
        coEngine.StandardInput.WriteLine("?");
        coEngine.StandardInput.Flush();
      }
    }

    /// <summary>
    /// Puts our chess engine into analysis mode.
    /// </summary>
    /// <param name="turnOn"></param>
    override public void Analyze(bool turnOn)
    {
      if (IsRunning())
      {

        if (coAnalyzing && !turnOn)
        {
          coAnalyzing = false;
          coEngine.StandardInput.WriteLine("nopost");
          coEngine.StandardInput.WriteLine("exit");
          coEngine.StandardInput.Flush();
        }
        else if (turnOn && !coAnalyzing)
        {
          coEngine.StandardInput.WriteLine("post");
          coEngine.StandardInput.WriteLine("analyze");
          coEngine.StandardInput.Flush();
          coAnalyzing = true;
        }
      }
    }
 
    /// <summary>
    /// Sends a chess move to the engine.
    /// </summary>
    /// <param name="move"></param>
    public new void Move(string move)
    {
      if (IsRunning())
      {
        coEngine.StandardInput.WriteLine(move);
        coEngine.StandardInput.Flush();
      }
    }
 
    public new bool IsRunning()
    {
      bool running = false;
      if (coEngine != null)
        running = !coEngine.HasExited;
      return running;
    }
    public new bool IsAnalyzing()
    {
      return coAnalyzing;
    }
    #endregion


  }
}
